---
title: Hooks
---

`nestjs-query` provides the following hooks that allow you to modify incoming requests.

* `@BeforeFindOne` - invoked before any `findOne` query.
* `@BeforeQueryMany` - invoked before any `queryMany` query.
* `@BeforeCreateOne` - invoked before any `createOne` mutation.
* `@BeforeCreateMany` - invoked before any `createMany` mutation.
* `@BeforeUpdateOne` - invoked before any `updateOne` mutation.
* `@BeforeUpdateMany` - invoked before any `updateMany` mutation.
* `@BeforeDeleteOne` - invoked before any `deleteOne` mutation.
* `@BeforeDeleteMany` - invoked before any `deleteMany` mutation.

In order to use a hook you only need to decorate your DTO with the corresponding decorator.

Each hook decorator can be provided one of the following:
 * A hook function
 * A class that extends `Hook`, when using a class you can use DI to access other services just like `guards`,
 `interceptors` or `pipes`.

:::warning
The graphql context by default only contains the incoming request!
:::

:::note
If you provide a custom `create` or `update` DTO you can also decorate those classes with corresponding decorators.
:::

:::note
All of the examples reference a GqlContext. This was defined for the sake of the example. It is recommended that you
define a custom type that represents the information in the context based on the guards and interceptors used in your
application.

We have defined our `GqlContext` as

```ts
export type GqlContext = { req: { headers: Record<string, string> } };
```
:::

## @BeforeCreateOne

The `@BeforeCreateOne` decorator can be used to modify incoming `createOne` mutations with information from the graphql
context.


### Hook Function

In this example we set the createdBy field based on the context.

```ts {7-10}
import { FilterableField, BeforeCreateOne, CreateOneInputType } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
import { GqlContext } from '../../interfaces';
import { getUserName } from '../../helpers';

@ObjectType('TodoItem')
@BeforeCreateOne((input: CreateOneInputType<TodoItemDTO>, context: GqlContext) => {
  input.input.createdBy = getUserName(context);
  return input;
})
export class TodoItemDTO {

 /**
 Other fields
 **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

### Hook Class

You can also provide a custom `Hook` class that can leverage `nestjs` dependency injection.

In this example we create a simple Hook that works with any type that has a `createdBy` property.
```ts
import { Injectable } from '@nestjs/common';
import { BeforeCreateOneHook, CreateOneInputType,} from '@nestjs-query/query-graphql';
import { GqlContext } from './auth/auth.guard';
import { AuthService } from './auth/auth.service';

interface CreatedBy {
  createdBy: string;
}

@Injectable()
export class CreatedByHook<T extends CreatedBy> implements BeforeCreateOneHook<T, GqlContext> {
  constructor(readonly authService: AuthService) {}

  async run(instance: CreateOneInputType<T>, context: GqlContext): Promise<CreateOneInputType<T>> {
    const createdBy = await this.authService.getUserEmail(context.userId);
    instance.input.createdBy = createdBy;
    return instance;
  }
}
```

Now we just provide the hook to the `BeforeCreateOne` decorator.

```ts {6}
import { FilterableField, BeforeCreateOne } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
import { CreatedByHook } from '../../hooks';

@ObjectType('TodoItem')
@BeforeCreateOne(CreatedByHook)
export class TodoItemDTO {

 /**
 Other fields
 **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

## @BeforeCreateMany

The `@BeforeCreateMany` decorator can be used to modify incoming `createMany` mutations with information from the
graphql context.


### Hook Function

In this example we set the createdBy field on each record based on the context.

```ts {7-11}
import { FilterableField, BeforeCreateMany, CreateManyInputType } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
import { GqlContext } from '../../interfaces';
import { getUserName } from '../../helpers';

@ObjectType('TodoItem')
@BeforeCreateMany((input: CreateManyInputType<TodoItemDTO>, context: GqlContext) => {
  const createdBy = getUserName(context);
  input.input = input.input.map((c) => ({ ...c, createdBy }));
  return input;
})
export class TodoItemDTO {

   /**
   Other fields
   **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

### Hook Class

You can also provide a custom `Hook` class that can leverage `nestjs` dependency injection.

In this example we create a simple Hook that works with any type that has a `createdBy` property.
```ts
import { Injectable } from '@nestjs/common';
import { BeforeCreateManyHook, CreateManyInputType,} from '@nestjs-query/query-graphql';
import { GqlContext } from './auth/auth.guard';
import { AuthService } from './auth/auth.service';

interface CreatedBy {
  createdBy: string;
}

@Injectable()
export class CreatedByHook<T extends CreatedBy> implements BeforeCreateManyHook<T, GqlContext> {
  constructor(readonly authService: AuthService) {}

  async run(instance: CreateManyInputType<T>, context: GqlContext): Promise<CreateManyInputType<T>> {
    const createdBy = await this.authService.getUserEmail(context.userId);
    instance.input = instance.input.map((c) => ({ ...c, createdBy }));
    return instance;
  }
}
```

Now we just provide the hook to the `BeforeCreateMany` decorator.

```ts {6}
import { FilterableField, BeforeCreateMany } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
import { CreatedByHook } from '../../hooks';

@ObjectType('TodoItem')
@BeforeCreateMany(CreatedByHook)
export class TodoItemDTO {

 /**
 Other fields
 **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

## @BeforeUpdateOne

The `@BeforeUpdateOne` decorator can be used to modify incoming `updateOne` mutations with information from the graphql
context.


### Hook Fnction

In this example we set the updatedBy field in the update.

```ts {7-10}
import { FilterableField, BeforeUpdateOne, UpdateOneInputType } from '@nestjs-query/query-graphql';
import { ObjectType } from '@nestjs/graphql';
import { GqlContext } from '../../interfaces';
import { getUserName } from '../../helpers';

@ObjectType('TodoItem')
@BeforeUpdateOne((input: UpdateOneInputType<TodoItemDTO>, context: GqlContext) => {
  input.update.updatedBy = getUserName(context);
  return input;
})
export class TodoItemDTO {

  /**
  Other fields
  **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

### Hook Class

You can also provide a custom `Hook` class that can leverage `nestjs` dependency injection.

In this example we create a simple Hook that works with any type that has a `updatedBy` property.
```ts
import { BeforeUpdateOneHook, UpdateOneInputType } from '@nestjs-query/query-graphql';
import { Injectable } from '@nestjs/common';
import { GqlContext } from './auth/auth.guard';
import { AuthService } from './auth/auth.service';

interface UpdatedBy {
  updatedBy: string;
}

@Injectable()
export class UpdatedByHook<T extends UpdatedBy> implements BeforeUpdateOneHook<T, GqlContext> {
  constructor(readonly authService: AuthService) {}

  async run(instance: UpdateOneInputType<T>, context: GqlContext): Promise<UpdateOneInputType<T>> {
    // eslint-disable-next-line no-param-reassign
    instance.update.updatedBy = await this.authService.getUserEmail(context.userId);
    return instance;
  }
}
```

Now we just provide the hook to the `BeforeUpdateOne` decorator.

```ts {6}
import { FilterableField, BeforeUpdateOne } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
import { CreatedByHook } from '../../hooks';

@ObjectType('TodoItem')
@BeforeUpdateOne(UpdatedByHook)
export class TodoItemDTO {

 /**
 Other fields
 **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

## @BeforeUpdateMany

The `@BeforeUpdateMany` decorator can be used to modify incoming `updateMany` mutations with information from the
graphql context.

### Hook Function

In this example we set the updatedBy field in the update.

```ts {7-10}
import { FilterableField, BeforeUpdateMany, UpdateManyInputType } from '@nestjs-query/query-graphql';
import { ObjectType } from '@nestjs/graphql';
import { GqlContext } from '../../interfaces';
import { getUserName } from '../../helpers';

@ObjectType('TodoItem')
@BeforeUpdateMany((input: UpdateManyInputType<TodoItemDTO, TodoItemDTO>, context: GqlContext) => {
  input.update.updatedBy = getUserName(context);
  return input;
})
export class TodoItemDTO {

  /**
  Other fields
  **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

### Hook Class

You can also provide a custom `Hook` class that can leverage `nestjs` dependency injection.

In this example we create a simple Hook that works with any type that has a `updatedBy` property.
```ts
import { BeforeUpdateManyHook, UpdateManyInputType } from '@nestjs-query/query-graphql';
import { Injectable } from '@nestjs/common';
import { GqlContext } from './auth/auth.guard';
import { AuthService } from './auth/auth.service';

interface UpdatedBy {
  updatedBy: string;
}

@Injectable()
export class UpdatedByHook<T extends UpdatedBy> implements BeforeUpdateManyHook<T, GqlContext> {
  constructor(readonly authService: AuthService) {}

  async run(instance: UpdateManyInputType<T, T>, context: GqlContext): Promise<UpdateManyInputType<T, T>> {
    // eslint-disable-next-line no-param-reassign
    instance.update.updatedBy = await this.authService.getUserEmail(context.userId);
    return instance;
  }
}
```

Now we just provide the hook to the `BeforeUpdateMany` decorator.

```ts {6}
import { FilterableField, BeforeUpdateMany } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
import { CreatedByHook } from '../../hooks';

@ObjectType('TodoItem')
@BeforeUpdateMany(UpdatedByHook)
export class TodoItemDTO {

 /**
 Other fields
 **/

  @FilterableField({ nullable: true })
  createdBy?: string;

  @FilterableField({ nullable: true })
  updatedBy?: string;
}

```

## Using Hooks In Custom Endpoints

You can also use hooks in custom endpoints by using the `HookInterceptor` along with
* `HookArgs` - Used to apply hooks to any query endpoint.
* `MutationHookArgs` - Used to apply hooks to any `mutation` that uses `MutationArgsType`

### Example

In this example we'll create an endpoint that marks all todo items that are currently not completed as completed.

To start we'll create our input types.

There are two types that are created
* The `UpdateManyTodoItemsInput` which extends the `UpdateManyInputType` this exposes an `update` and `filter` field just like the `updateMany` endpoints that are auto generated.
* The `UpdateManyTodoItemsArgs` which extends `MutationArgsType`, this provides a uniform interface for all mutations
 ensuring that the argument provided to the mutation is named `input`.

```ts title="todo-item/types.ts"
import { MutationArgsType, UpdateManyInputType } from '@nestjs-query/query-graphql';
import { ArgsType, InputType } from '@nestjs/graphql';
import { TodoItemDTO } from './dto/todo-item.dto';
import { TodoItemUpdateDTO } from './dto/todo-item-update.dto';

// create the base input type
@InputType()
export class MarkTodoItemsAsCompletedInput extends UpdateManyInputType(TodoItemDTO, TodoItemUpdateDTO) {}

// Wrap the input in the MutationArgsType to provide a uniform format for all mutations
// The `MutationArgsType` is a thin wrapper that names the args as input
@ArgsType()
export class MarkTodoItemsAsCompletedArgs extends MutationArgsType(UpdateManyTodoItemsInput) {}
```
Now we can use our new types in the resolver.

```ts title="todo-item/todo-item.resolver.ts" {16,17}
import { InjectQueryService, mergeFilter, QueryService, UpdateManyResponse } from '@nestjs-query/core';
import { HookTypes, HookInterceptor, MutationHookArgs, UpdateManyResponseType } from '@nestjs-query/query-graphql';
import { UseInterceptors } from '@nestjs/common';
import { Mutation, Resolver } from '@nestjs/graphql';
import { TodoItemDTO } from './dto/todo-item.dto';
import { TodoItemEntity } from './todo-item.entity';
import { MarkTodoItemsAsCompletedArgs } from './types';
import { TodoItemUpdateDTO } from './dto/todo-item-update.dto';

@Resolver(() => TodoItemDTO)
export class TodoItemResolver {
  constructor(@InjectQueryService(TodoItemEntity) readonly service: QueryService<TodoItemDTO>) {}

  // Set the return type to the TodoItemConnection
  @Mutation(() => UpdateManyResponseType())
  @UseInterceptors(HookInterceptor(HookTypes.BEFORE_UPDATE_MANY, TodoItemUpdateDTO))
  markTodoItemsAsCompleted(@MutationHookArgs() { input }: MarkTodoItemsAsCompletedArgs): Promise<UpdateManyResponse> {
    return this.service.updateMany(
      { ...input.update, completed: true },
      mergeFilter(input.filter, { completed: { is: false } }),
    );
  }
}

```
The first thing to notice is the

```ts
@UseInterceptors(HookInterceptor(HookTypes.BEFORE_UPDATE_MANY, TodoItemUpdateDTO))
```

This interceptor adds the correct hook to the `context` to be used by the param decorator.

There are a few things to take note of:
* The `HookTypes.BEFORE_UPDATE_MANY` lets the interceptor know we are wanting the BeforeUpdateMany hook to be used
for this mutation.
* We use the `TodoItemUpdateDTO`, that is because the `@BeforeUpdateMany` decorator was put on the
`TodoItemUpdateDTO` not the `TodoItemDTO`.

:::warning
When using the HookInterceptor you must use the DTO that you added the hook decorator to.
:::

:::note
In this example we bind the `BEFORE_UPDATE_MANY` hook, you can use any of the hooks available to bind to the correct
one when `creating`, `updating`, or `deleting` records.
:::

The next piece is the

```ts
@MutationHookArgs() { input }: UpdateManyTodoItemsArgs
```
By using the `MutationHookArgs` decorator we ensure that the hook is applied to the arguments adding any additional
fields to the update.

Finally we invoke the service `updateMany` with a filter that ensures we only update `TodoItems` that are completed,
and add an setting `completed` to true to the update

```ts
return this.service.updateMany(
  { ...input.update, completed: false },
  mergeFilter(input.filter, { completed: { is: false } }),
);
```
